package com.weizhu.swufer.core.cluster;

import com.weizhu.swufer.constant.SwuferConstant;
import com.weizhu.swufer.core.client.Invoker;
import com.weizhu.swufer.core.entity.InvokeParam;
import com.weizhu.swufer.core.filter.FilterChain;
import com.weizhu.swufer.core.filter.FilterManager;
import com.weizhu.swufer.core.loadbalance.LoadBalancer;
import com.weizhu.swufer.core.loadbalance.RandomLoadBalancer;
import com.weizhu.swufer.core.rpc.RpcRequest;
import com.weizhu.swufer.core.server.SwuferBootstrap;
import com.weizhu.swufer.core.util.BeanUtil;
import com.weizhu.swufer.core.util.SpringUtils;

import java.util.Properties;

public abstract class AbstractClusterInvoker extends Invoker{

    private Class<?> loadBalancerClass;

    LoadBalancer loadBalancer;

    public Class<?> getLoadBalancerClass() {
        return loadBalancerClass;
    }

    public void setLoadBalancerClass(Class<?> loadBalancerClass) {
        this.loadBalancerClass = loadBalancerClass;
        initLoadBalancer();
    }

    private LoadBalancer initLoadBalancer(){
        if (loadBalancerClass == null){
            Properties properties = SwuferBootstrap.getInstance().getProperties();
            String property = properties.getProperty(SwuferConstant.PROPERTIES_LOADBALANCER);
            if (property != null && !property.contains(".")){
                property = "com.weizhu.swufer.core.loadbalance." + property;
            }

            if (property != null){
                try {
                    loadBalancerClass = Class.forName(property);
                }catch (ClassNotFoundException e){
                    throw new IllegalStateException("load balancer class " + property + " not exist");
                }
            }else {
                loadBalancerClass = RandomLoadBalancer.class;
            }
            if (!LoadBalancer.class.isAssignableFrom(loadBalancerClass)){
                throw new IllegalStateException("class " + loadBalancerClass.getName() + " has not implements LoadBalancer.class");
            }

        }
        if (SpringUtils.loadClassFromSpring(loadBalancerClass) != null){
            return (LoadBalancer) SpringUtils.loadClassFromSpring(loadBalancerClass);
        }
        LoadBalancer loadBalancer = (LoadBalancer) BeanUtil.createSingletonInstance(loadBalancerClass);
        this.loadBalancer = loadBalancer;
        return loadBalancer;
    }

    @Override
    public Object invoke(InvokeParam invokeParam) throws Exception {
        initLoadBalancer();
        return doFilterInvoke(invokeParam);

    }

    public Object doFilterInvoke(InvokeParam invokeParam) throws Exception {
        FilterChain filterChain = FilterManager.getInstance().buildClientFilterChain();
        filterChain.addFilter(this);
        return filterChain.doFilter(invokeParam);
    }

    @Override
    public Object doFilter(InvokeParam invokeParam, FilterChain filterChain) {
        String address = loadBalancer.select(invokeParam);
        return doInvoke(invokeParam,address);
    }

    public abstract Object doInvoke(InvokeParam invokeParam,String address);
}
